package com.alan.springbootbase.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @author Alan
 * @Description
 * @date 2021年02月03日 16:18
 */
@Data
@Entity//表明这是一个持久化类
@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"})//json 序列化时忽略 bean 中的一些不需要转化的属性
@Table(name="user_jpa")//主要是映射表名对应的数据库表名JPA_CUSTOMER默认情况下可以不写表名与持久化类名相同;【强制】表名、字段名必须使用小写字母或数字，禁止出现数字开头
public class User extends BaseEntity{
    private static final long serialVersionUID = 1L;

    /**
     * 用户名
     */
    @Column(nullable = false, unique = true ,columnDefinition = "varchar(100) COMMENT '用户名'")
    private String userName;
    /**
     * 密码
     */
    @Column(nullable = false)
    private String passWord;

    @Column(nullable = false, unique = true)
    private String email;
    @Column(unique = true)
    private String nickName;


    /**
     *【强制】小数类型为 decimal，禁止使用 float 和 double。
     * float 和 double 在存储的时候，存在精度损失的问题，很可能在值的比较时，得到不
     * 正确的结果。如果存储的数据范围超过 decimal 的范围，建议将数据拆成整数和小数分开存储。
     */
    @Column(name = "bd")
    private BigDecimal bd;

    /**
     * 表达是与否概念的字段，必须使用 is_xxx 的方式命名，数据类型是 unsigned tinyint（1 表示是，0 表示否）。
     *   说明：任何字段如果为非负数，必须是 unsigned。
     */
    @Column(name = "is_deleted",columnDefinition = "tinyint unsigned")
    private Integer deleted;

    /**
     *【强制】如果存储的字符串长度几乎相等，使用 char 定长字符串类型。
     *
     * 状态
     */
    @Column(name = "state",columnDefinition = "char(2)")
    private String state;

    /**
     * 【强制】varchar 是可变长字符串，不预先分配存储空间，长度不要超过 5000，如果存储长
     *  度大于此值，定义字段类型为 text，独立出来一张表，用主键来对应，避免影响其它字段索引效率
     *
     *  信息
     */
    @Column(name = "info",columnDefinition = "text")
    private String info;



    /**
     * 关于Date类型的处理
     * 总结Alan：DATE、TIME可直接使用，数据库和返回的字段格式均正常；TIMESTAMP可生成数据库中datetime类型字段，但是返回类型需要格式化
     * 数据库的字段类型有date、time、datetime
     * 而Temporal注解的作用就是帮Java的Date类型进行格式化，一共有三种注解值：
     * 第一种：@Temporal(TemporalType.DATE)——>实体类会封装成日期“yyyy-MM-dd”的 Date类型。-数据库：date。
     * 第二种：@Temporal(TemporalType.TIME)——>实体类会封装成时间“hh-MM-ss”的 Date类型。-数据库：time
     * 第三种：@Temporal(TemporalType.TIMESTAMP)——>实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型。-数据库：datetime。
     */
    @Column(name = "t_time")
    @Temporal(TemporalType.TIME)
    private Date tTime;

    @Column(name = "t_date")
    @Temporal(TemporalType.DATE)
    private Date tDate;

    @Column(name = "t_datetime")
    @Temporal(TemporalType.TIMESTAMP)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date tDatetime;





    /**
     * 【推荐】表的命名最好是加上“业务名称_表的作用”。
     * 【推荐】库名与应用名称尽量一致。
     * 【推荐】如果修改字段含义或对字段表示的状态追加时，需要及时更新字段注释。
     * 【推荐】字段允许适当冗余，以提高查询性能，但必须考虑数据一致。冗余字段应遵循：
     *      1）不是频繁修改的字段。
     *      2）不是 varchar 超长字段，更不能是 text 字段。
     *      正例：商品类目名称使用频率高，字段长度短，名称基本一成不变，可在相关联的表中冗余存储类目名称，避免关联查询。
     * 【推荐】单表行数超过 500 万行或者单表容量超过 2GB，才推荐进行分库分表。
     *  说明：如果预计三年后的数据量根本达不到这个级别，请不要在创建表时就分库分表。
     */

    /**
     *  Column属性详解：
     *  name:定义了被标注字段在数据库表中所对应字段的名称；
     *  unique:表示该字段是否为唯一标识，默认为false。如果表中有一个字段需要唯一标识，则既可以使用该标记，也可以使用@Table标记中的@UniqueConstraint。
     *  nullable:表示该字段是否可以为null值，默认为true。
     *  Column(name = "name",columnDefinition = "varchar(100) COMMENT '用户名'")
     *  insertable:表示在使用“INSERT”脚本插入数据时，是否需要插入该字段的值。
     *  updatable:表示在使用“UPDATE”脚本插入数据时，是否需要更新该字段的值。insertable和updatable属性一般多用于只读的属性，例如主键和外键等。这些字段的值通常是自动生成的。
     *  columnDefinition（大多数情况，几乎不用）:表示创建表时，该字段创建的SQL语句，一般用于通过Entity生成表定义时使用。（也就是说，如果DB中表已经建好，该属性没有必要使用。）
     */

    /**
     * 实体类用int还是Integer
     * 1.Integer默认值是null，可以区分未赋值和值为0的情况.需要区分未赋值的情况下用Integer
     * 2.加减乘除运算比较多的情况下,用int.用Integer需要拆装箱,比较耗性能
     * 3.默认值为0的场景用int.比如统计报表的场景下,没有就是0.这时用int.
     * 4.容器里面用Integer.比如List<Integer>
     * 5.接口入参对象QO里面的属性,用Integer.这是面向对象思想.保持QO里面的属性都是对象.避免接口被调用时出现麻烦.
     */

    /**
     *【强制】表必备三字段：id, gmt_create, gmt_modified。
     * 说明：其中 id 必为主键，类型为 bigint unsigned、单表时自增、步长为 1。gmt_create,
     * gmt_modified 的类型均为 datetime 类型，前者现在时表示主动创建，后者过去分词表示被
     * 动更新。
     */

    /**
     * 【参考】合适的字符存储长度，不但节约数据库表空间、节约索引存储，更重要的是提升检索速度。
     *      正例：如下表，其中无符号值可以避免误存负数，且扩大了表示范围。
     *      对象      年龄区间        类型                  字节              表示范围
     *      人       150 岁之内     tinyint unsigned        1 无符号值：     0 到 255
     *      龟        数百岁        smallint unsigned       2 无符号值：     0 到 65535
     *      恐龙化石   数千万年       int unsigned          4 无符号值：       0 到约 42.9 亿
     *      太阳      约 50 亿年     bigint unsigned         8 无符号值：     0 到约 10 的 19 次方
     */

}
